#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
#include "numeric.h"



namespace LuaNumeric {
	void open_luaVector(sol::table& module);
	void open_luaComplex(sol::table& module);
	void open_luaGlobal(sol::table& module);
	void open_luaEigen(sol::table& module);
	void open_luaSparseEigen(sol::table& module);
	void open_luaFT(sol::table& module);
	void open_luaMap(sol::table& module);
	void open_luaPoint(sol::table& module);
	void open_luaTensor(sol::table& module);

	sol::table open_luaNumericLua(sol::this_state L) {
		sol::state_view lua(L);

		sol::table module=lua.script(R"(
				local module={};
				debug = require"debug"
				function module.deserialize(str)
					str = 'return '.. str;
					local __nl__ = nl;
					nl = module;					
					f = assert( load(str), 'load string failed');
					if __nl__ ~= nil then nl = __nl__ end; 	
					return f();
				end

				function module.NewVector(self)
					local cobj = module.new_vector()
					for k,v in pairs(self) do
						if type(v)=="number" then
							cobj:add(v)
						end
					end
					return cobj
				end
				
				function module.NewComplexVector(self)
					local cobj = module.new_cvector()
					for k,v in pairs(self) do
						if type(v)=="number" then
							cobj:push_back(v)
						end
					end
					return cobj
				end
				
				function module.LinearSpace(min,max,num, arraytype)
					assert( type(num) == "number", "num is not set" );
					assert( num >= 1, "num is wrong" );
					local cobj;
					if arraytype == nil or arraytype ~= "complex"  then
						assert( type(min) == "number", "min is not set" );
						assert( type(max) == "number", "max is not set" );
						cobj = module.new_vector(num);
					end
				
					if arraytype == "complex" then
						cobj = module.new_cvector(num)
						min = module.new_complex(min)
						max = module.new_complex(max)
					end
				
					if num == 1 then
						cobj[1] = min;
					else
						local delta = (max-min)/(num-1);
						for ii=1, #cobj do
							cobj[ii] = min + (ii-1) * delta ;
						end
					end
					return cobj;
				end
				return module;
		)");

		//sol::table module = lua.create_table();
		//module["LinearSpace"] = lua["module"];
		open_luaVector(module);
		open_luaComplex(module);
		open_luaGlobal(module);
		open_luaEigen(module);
		open_luaSparseEigen(module);
		open_luaFT(module);
		open_luaMap(module);
		open_luaPoint(module);
		open_luaTensor(module);
		return module;
	}
}



extern "C" int luaopen_luaNumeric(lua_State* L)
{
	return sol::stack::call_lua(L, 1, LuaNumeric::open_luaNumericLua );
}

